home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Tools & Utilities
/
Collection of Tools and Utilities.iso
/
edit
/
xvisrc.zip
/
MAP.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-07-28
|
10KB
|
479 lines
/* Copyright (c) 1990,1991,1992 Chris and John Downey */
#ifndef lint
static char *sccsid = "@(#)map.c 2.1 (Chris & John Downey) 7/29/92";
#endif
/***
* program name:
xvi
* function:
PD version of UNIX "vi" editor, with extensions.
* module name:
map.c
* module function:
Keyboard input/pushback routines, "map" command.
Note that we provide key mapping through a different interface,
so that cursor key mappings etc do not show up to the user.
This works by having a two-stage process; first keymapping is
done, and then the result is fed through the normal mapping
process. The intent of the keymapping stage is to convert
machine-local keys into a standard form.
* bug:
If a map fails, we just pass all characters which had already
been accepted, plus the character which caused the mismatch,
straight through. This is not quite correct because we might
have got a good match starting at the very next character, i.e.
if we have mapped
foo to bar
and get input "ffoo", then the seconf 'f' will cause the map to
fail and both characters will go through, and so the whole thing
will pass through unmapped.
The only way around this problem is to introduce another flexbuf
on the input side of the keymap stage, to give us somewhere to
put all characters after the first, when a map fails. I.e. in the
case above, we would pass the first 'f' through to the "mp_dest"
flexbuf, and stuff any characters after that into "mp_src".
* history:
STEVIE - ST Editor for VI Enthusiasts, Version 3.10
Originally by Tim Thompson (twitch!tjt)
Extensive modifications by Tony Andrews (onecom!wldrdg!tony)
Heavily modified by Chris & John Downey
***/
#include "xvi.h"
/*
* This is the fundamental structure type which is used
* to hold mappings from one string to another.
*/
typedef struct map {
struct map *m_next;
char *m_lhs; /* lhs of map */
char *m_rhs; /* rhs of map */
unsigned int m_same; /* no characters same as next map */
} Map;
/*
* This structure holds a current position while scanning a map list.
* It is also effectively used to form a chain of mapping structures,
* interconnected with flexbufs.
*/
typedef struct mpos {
Map *mp_map;
int mp_index;
Flexbuf *mp_src;
Flexbuf *mp_dest;
} Mpos;
/*
* Two mapping structures exist; one for "map", and one for "map!".
*/
static Map *cmd_map = NULL;
static Map *ins_map = NULL;
static Map *key_map = NULL;
/*
* This is the position in cmd_map/ins_map when we are waiting for
* the next character. When not waiting, mp_map is NULL (as at start).
* Also stores flexbuf pointers for input and output at each stage.
*/
static Flexbuf getcbuff;
static Flexbuf inputbuff;
static Mpos npos = { NULL, 0, &inputbuff, &getcbuff };
static Mpos kpos = { NULL, 0, NULL, &inputbuff };
/*
* This is used for "display" mode; it records the current map which
* is being displayed. It is used by show_map().
*/
static Map *curmap;
static char *show_map P((void));
static void mapthrough P((void));
static bool_t process_map P((int, Mpos *));
static void calc_same P((Map *));
static void map_failed P((Mpos *));
static void insert_map P((Map **, char *, char *, bool_t));
static void delete_map P((Map **, char *));
/*VARARGS1*/
/*PRINTFLIKE*/
void
stuff
#ifdef __STDC__
(char *format, ...)
#else /* not __STDC__ */
(format, va_alist)
char *format;
va_dcl
#endif
{
va_list argp;
VA_START(argp, format);
(void) vformat(npos.mp_dest, format, argp);
va_end(argp);
}
int
map_getc()
{
return(flexempty(npos.mp_dest) ? EOF : flexpopch(npos.mp_dest));
}
void
map_char(c)
register int c;
{
/*
* Send the input character through the keymap list.
*/
if (kpos.mp_map == NULL) {
kpos.mp_map = key_map;
kpos.mp_index = 0;
}
if (process_map(c, &kpos) == FALSE) {
/*
* Send resulting output through the normal map list.
*/
kpos.mp_map = NULL;
mapthrough();
}
}
/*
* Process any characters in the input buffer through the
* cmd_map/ins_map lists into the output buffer, whence
* characters go into the editor itself.
*/
static void
mapthrough()
{
while (!flexempty(npos.mp_src)) {
if (npos.mp_map == NULL) {
if (State == NORMAL) {
npos.mp_map = cmd_map;
} else if (State == INSERT || State == REPLACE) {
npos.mp_map = ins_map;
}
npos.mp_index = 0;
}
if (process_map(flexpopch(npos.mp_src), &npos) == FALSE) {
npos.mp_map = NULL;
}
}
}
/*
* Process the given character through the maplist pointed to
* by the given position. Returns TRUE if we should continue,
* or FALSE if this attempt at mapping has terminated (either
* due to success or definite failure).
*/
static bool_t
process_map(c, pos)
register int c;
register Mpos *pos;
{
register Map *tmp;
register int ind;
ind = pos->mp_index;
for (tmp = pos->mp_map; tmp != NULL; tmp = tmp->m_next) {
if (tmp->m_lhs[ind] == c) {
if (tmp->m_lhs[ind + 1] == '\0') {
/*
* Found complete match. Insert the result into
* the appropriate output buffer, according to
* whether "remap" is set or not.
*/
(void) lformat((Pb(P_remap) && pos->mp_src != NULL) ?
pos->mp_src : pos->mp_dest, "%s", tmp->m_rhs);
return(FALSE);
} else {
/*
* Found incomplete match,
* keep going.
*/
pos->mp_map = tmp;
pos->mp_index++;
}
return(TRUE);
}
/*
* Can't move on to next map entry unless the m_same
* field is sufficient that the match so far would
* have worked.
*/
if (tmp->m_same < ind) {
break;
}
}
map_failed(pos);
/*
* Don't forget to re-stuff the character we have just received.
*/
(void) flexaddch(pos->mp_dest, c);
return(FALSE);
}
void
map_timeout()
{
if (kpos.mp_map != NULL) {
map_failed(&kpos);
mapthrough();
} else {
map_failed(&npos);
}
}
bool_t
map_waiting()
{
return(kpos.mp_map != NULL || npos.mp_map != NULL);
}
/*
* This routine is called when a timeout has occurred.
*/
static void
map_failed(pos)
Mpos *pos;
{
register char *cp;
register Flexbuf *fbp;
register int i;
if (pos->mp_map != NULL) {
fbp = pos->mp_dest;
for (i = 0, cp = pos->mp_map->m_lhs; i < pos->mp_index; i++) {
(void) flexaddch(fbp, cp[i]);
}
pos->mp_map = NULL;
}
}
/*
* Insert the key map lhs as mapping into rhs.
*/
void
xvi_keymap(lhs, rhs)
char *lhs;
char *rhs;
{
insert_map(&key_map, lhs, rhs, FALSE);
}
/*
* Insert the entry "lhs" as mapping into "rhs".
*/
void
xvi_map(argc, argv, exclam, inter)
int argc;
char *argv[];
bool_t exclam;
bool_t inter;
{
switch (argc) {
case 2: /* valid input */
if (argv[0][0] == '\0') {
if (inter) {
show_message(curwin, "Usage: map lhs rhs");
}
return;
}
insert_map(exclam ? &ins_map : &cmd_map, argv[0], argv[1], inter);
break;
case 0:
curmap = exclam ? ins_map : cmd_map;
disp_init(curwin, show_map, (int) curwin->w_ncols, FALSE);
break;
default:
if (inter) {
show_message(curwin, "Wrong number of arguments to map");
}
}
}
static void
insert_map(maplist, left, right, interactive)
Map **maplist;
char *left;
char *right;
bool_t interactive;
{
char *lhs; /* saved lhs of map */
char *rhs; /* saved rhs of map */
Map *mptr; /* new map element */
Map **p; /* used for loop to find position */
int rel;
lhs = strsave(left);
if (lhs == NULL || (rhs = strsave(right)) == NULL) {
if (interactive) {
show_message(curwin, "no memory for that map");
}
return;
}
mptr = (Map *) alloc(sizeof(Map));
if (mptr == NULL) {
free(lhs);
free(rhs);
return;
}
mptr->m_lhs = lhs;
mptr->m_rhs = rhs;
p = maplist;
if ((*p) == NULL || strcmp((*p)->m_lhs, lhs) > 0) {
/*
* Either there are no maps yet, or the one
* we want to enter should go at the start.
*/
mptr->m_next = *p;
*p = mptr;
calc_same(mptr);
} else if (strcmp((*p)->m_lhs, lhs) == 0) {
/*
* We need to replace the rhs of the first map.
*/
free(lhs);
free((char *) mptr);
free((*p)->